﻿using CommonNet48.CommonModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace CommonNet48.Net
{
    public class MyUDPServer : IDisposable
    {
        /// <summary>
        /// 构造
        /// </summary>
        public MyUDPServer() : this(IPAddress.Any, 0) { }

        /// <summary>
        /// 构造
        /// </summary>
        /// <param name="port">端口</param>
        public MyUDPServer(int port) : this(IPAddress.Any, port) { }

        /// <summary>
        /// 构造
        /// </summary>
        /// <param name="ipa">IPAddress</param>
        /// <param name="port">port</param>
        public MyUDPServer(IPAddress ipa, int port)
        {
            _Server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            IPEndPoint localIPEP = new IPEndPoint(ipa, port);
            _Server.Bind(localIPEP);
        }

        /// <summary>
        /// 构造
        /// </summary>
        /// <param name="ip">ip地址</param>
        /// <param name="port">端口</param>
        public MyUDPServer(string ip, int port)
        {
            _Server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            IPAddress ipa;
            var bRet = IPAddress.TryParse(ip, out ipa);
            if (!bRet) ipa = IPAddress.Any;
            IPEndPoint localIPEP = new IPEndPoint(ipa, port);
            _Server.Bind(localIPEP);
        }

        /// <summary>
        /// 服务Socket对象
        /// </summary>
        private Socket _Server;

        /// <summary>
        /// 停止标记
        /// </summary>
        private bool _StopFlag = false;

        /// <summary>
        /// 开始服务
        /// </summary>
        /// <returns></returns>
        public void StartServer()
        {
            try
            {
                OnMessage?.Invoke(new MyMessage<string>("服务已启动！", MyMsgType.Info));
                this.IsRuning = true;
                _StopFlag = false;
                while (!_StopFlag)
                {
                    if (_Server.Available > 0)
                    {
                        byte[] buffer = new byte[4096];
                        EndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0);
                        var len = _Server.ReceiveFrom(buffer, ref remoteEP);
                        IPEndPoint ipe = remoteEP as IPEndPoint;
                        string msg = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} 收到来自{ipe.Address}:{ipe.Port}的消息:{DataEncoding.GetString(buffer.Take(len).ToArray())}";
                        OnMessage?.Invoke(new MyMessage<string>(msg, MyMsgType.Info));
                        OnProcessData?.Invoke(buffer, len, remoteEP);
                    }
                }
            }
            catch (Exception ex)
            {
                OnMessage?.Invoke(new MyMessage<string>(ex.Message, MyMsgType.Error));
            }
            finally
            {
                this.IsRuning = false;
                OnMessage?.Invoke(new MyMessage<string>("服务已停止！", MyMsgType.Info));
            }
        }

        public async void SendTo(byte[] data, EndPoint remoteEP)
        {
            await Task.Run(() => _Server.SendTo(data, remoteEP));
        }

        public async void SendTo(string msg, EndPoint remoteEP)
        {
            byte[] data = DataEncoding.GetBytes(msg);
            await Task.Run(() => _Server.SendTo(data, remoteEP));
        }

        /// <summary>
        /// 停止服务
        /// </summary>
        public async void StopServer()
        {
            await Task.Run(() => _StopFlag = true);
        }

        /// <summary>
        /// 释放
        /// </summary>
        public void Dispose()
        {
            _Server?.Close();
        }

        /// <summary>
        /// 消息传递事件
        /// </summary>
        public Action<MyMessage<string>> OnMessage { get; set; }

        /// <summary>
        /// 数据处理委托
        /// </summary>
        public Action<byte[], int, EndPoint> OnProcessData { get; set; }

        /// <summary>
        /// 字符编码规则
        /// </summary>
        public Encoding DataEncoding { get; set; } = Encoding.UTF8;

        /// <summary>
        /// 是否服务正在运行
        /// </summary>
        public bool IsRuning { get; private set; } = false;
    }
}
